package org.grc.app.z_project.z_framework.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/** 
 * 流水码生成类
 * 
 * @author grc
 * @since 1.0-SNAPSHOT
 */
public class SerialNumberUtil{

	/**
	 * 根据类型获取流水码 默认日期格式为yyMM
	 * @param type 
	 * @param sysFlg 流水码前缀
	 * @param serialNumberBitCount 流水码位数
	 */
	public static String getSerialNumber(String type, String sysFlg, int serialNumberBitCount) {
		return getSerialNumber("yyMM", type, sysFlg, serialNumberBitCount);
	}

	/**
	 * 根据类型获取流水码
	 */
	public static String getSerialNumber(String format, String type, String sysFlg, int serialNumberBitCount) {
		String result = "";
		DateNumber dn = (DateNumber)SerializableTool.getObject(DateNumber.class);
		String suffix = sysFlg;
		String dateStr = dn.returnDateNumber(format);
		SerialNumber sn = (SerialNumber)SerializableTool.getObject(SerialNumber.class);
		String serialStr = sn.getSerialNumberByType(type,serialNumberBitCount);
		SerializableTool.saveObject(sn);
		SerializableTool.saveObject(dn);
		result = suffix + dateStr + serialStr;
		return result;
	}
}

/** 
 * @ClassName: SerialNumber 
 * @Description: TODO(流水码储存类) 
 * @author grc 
 * @date 2016年3月3日 上午10:45:54 
 * @version 1.0 
 */
class SerialNumber implements Serializable{


	/** 
	 * @Fields serialVersionUID : TODO(用一句话描述这个变量表示什么) 
	 */ 
	private static final long serialVersionUID = 1L;

	/** 
	 * @Fields serialNumber : TODO(存储的序列化号码) 
	 */ 
	private int serialNumber = 0;

	/** 
	 * @Fields storeMap : TODO(存储流水码的map属性) 
	 */ 
	private Map<String, Long> storeMap = new HashMap<String,Long>();

	public SerialNumber(){
	}

	public String getSerialNumberByType(String type, int serialNumberBitCount){

		if(storeMap.containsKey(type))
		{
			storeMap.put(type, storeMap.get(type)+1);
		}
		else
		{
			storeMap.put(type, 0L);
		}
		return addZero(storeMap.get(type), serialNumberBitCount);
	}

	private String addZero(long num, int serialNumberBitCount){

		String result = "";

		long serialNumber = num;

		int tmp = 1;

		for(int i=0 ; i<serialNumberBitCount ; i++)
		{
			tmp *= 10;
		}
		String tmpString = (tmp+serialNumber+"");

		result = tmpString.substring(1, tmpString.length());

		return result;
	}
	/** 
	 * @Title: returnSerialNumber 
	 * @Description: TODO(返回流水码) 
	 * @param serialNumberBitCount
	 * @return   
	 */
	private String returnSerialNumber(int serialNumberBitCount){

		String result = "";

		int serialNumber = getSerialNumber();
		setSerialNumber(serialNumber+1);

		int tmp = 1;

		for(int i=0 ; i<serialNumberBitCount ; i++)
		{
			tmp *= 10;
		}
		String tmpString = (tmp+serialNumber+"");

		result = tmpString.substring(1, tmpString.length());
		return result;
	}


	private int getSerialNumber() {
		return this.serialNumber;
	}

	private void setSerialNumber(int serialNumber) {
		this.serialNumber = serialNumber;
	}
	private Map<String, Long> getStoreMap() {
		return storeMap;
	}

	private void setStoreMap(Map<String, Long> storeMap) {
		this.storeMap = storeMap;
	}
}

/** 
 * @ClassName: DateNumber 
 * @Description: TODO(日期流水码生成类) 
 * @author grc 
 * @date 2016年3月3日 下午3:56:29 
 * @version 1.0 
 */
class DateNumber implements Serializable{

	/** 
	 * @Fields serialVersionUID : TODO(用一句话描述这个变量表示什么) 
	 */ 
	private static final long serialVersionUID = 1L;

	/** 
	 * @Fields calendar_old : TODO(用一句话描述这个变量表示什么) 
	 */ 
	private Calendar calendar_old = Calendar.getInstance();

	public DateNumber(){
		
	}

	public String returnDateNumber(String format){

		int field = 0;
		switch (format) {
		case "yyMMddhhmmss":
			field = Calendar.SECOND;
			break;
		case "yyMMddhhmm":
			field = Calendar.MINUTE;
			break;
		case "yyMMddhh":
			field = Calendar.HOUR_OF_DAY;
			break;
		case "yyMMdd":
			field = Calendar.DAY_OF_YEAR;
			break;
		case "yyMM":
			field = Calendar.MONTH;
			break;
		case "yy":
			field = Calendar.YEAR;
			break;

		default:
			field = Calendar.MONTH;
			break;
		}
		
		deleteSerialNumberFile(field);
		return getDateNumber(format);
	}
	
	private void deleteSerialNumberFile (int field){
		Calendar calendar_now = Calendar.getInstance();
		if(calendar_now.get(field) - calendar_old.get(field) > 0)
		{
			SerializableTool.deleteFile(SerialNumber.class);
		}
		calendar_old = calendar_now;
	}
	
	private String getDateNumber(String format){
		
		SimpleDateFormat sdft = null;
		if(format == null)
		{
			sdft = new SimpleDateFormat("yyMMddhhmmss"); 
		}
		else
		{
			sdft = new SimpleDateFormat(format); 
		}

		Date nowdate = new Date();  
		String str = sdft.format(nowdate);  

		return str;
	}
}

/** 
 * @ClassName: SerializableUtil 
 * @Description: TODO(这里用一句话描述这个类的作用) 
 * @author grc 
 * @date 2016年3月7日 下午3:43:50 
 * @version 1.0 
 */
class SerializableTool {

	private static String basePath = "serializable";

	public static void mkdir(){
		File file =new File(basePath);    
		//如果文件夹不存在则创建    
		if  (!file .exists()  && !file .isDirectory())      
		{       
			//System.out.println(file + "//不存在");  
			file .mkdir();
		} else   
		{  
			//System.out.println(file + "//目录存在");  
		} 
	}
	public static void deleteFile (Class<?> clazz){

		mkdir();

		String filePath = basePath + "/" + clazz.getName();
		File file = new File(filePath);

		if(file.exists())
		{
			file.delete();
		}

	}
	public static boolean ifExistsSerializableFile(Class<?> clazz){

		mkdir();

		String filePath = basePath + "/" + clazz.getName();
		File file = new File(filePath);
		if(file.exists())
		{
			return true;
		}

		return false;
	}

	public static void createSerializableFileIfNotExists(Class<?> clazz){
		mkdir();

		String filePath = basePath + "/" + clazz.getName();
		File file = new File(filePath);
		if(!file.exists())
		{
			try {
				ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));

				out.flush();
				out.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public static void saveObject(Object o){

		String filePath = basePath + "/" + o.getClass().getName();
		try {
			ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filePath));
			out.writeObject(o);
			out.flush();
			out.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public static Object readObject(Class<?> clazz){ 
		mkdir();

		String filePath = basePath + "/" + clazz.getName();
		Object object = null;
		try {
			ObjectInputStream oin = new ObjectInputStream(new FileInputStream(filePath));
			object = oin.readObject();

			oin.close();
		} catch (IOException | ClassNotFoundException e) {
			e.printStackTrace();
		} 

		return object;
	}
	public static Object getObject(Class<?> clazz){ 

		Object object = null;

		if(ifExistsSerializableFile(clazz))
		{
			object = readObject(clazz);
		}
		else
		{
			createSerializableFileIfNotExists(clazz);
			try {
				object = clazz.newInstance();
			} catch (InstantiationException | IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			saveObject(object);
		}

		return object;
	}
}